package bucket

import (
	"bytes"
	syncd "code.google.com/p/cloud9lib/syncd/httpd"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"math/rand"
	"net/url"
	"strings"
	"time"
)

type URLBucket struct {
	Items map[string]*url.URL
	feed  string
}

func NewURLBucket(feed string) *URLBucket {
	syncd.AddFeed(feed)
	return &URLBucket{make(map[string]*url.URL), feed}
}

func (b URLBucket) CopyFrom(urlstr string) error {

	resp, err := http.Get(urlstr)

	if err != nil {
		return err
	}

	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return errors.New("bucket not found at " + urlstr)
	}

	text, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return err
	}

	log.Println(string(text))

	err = json.Unmarshal(text, &b.Items)

	if err != nil {
		return err
	}

	return nil
}

func (b URLBucket) Get(id string) (io.Reader, int, error) {

	url, ok := b.Items[id]

	if !ok {
		return nil, 404, errors.New("resource not found")
	}

	return strings.NewReader(url.String()), 200, nil
}

func (b URLBucket) Post(body io.Reader) (string, int, error) {

	id := time.Now().String() + string(rand.Int())

	data, err := ioutil.ReadAll(body)

	if err != nil {
		return id, 500, errors.New("couldn't read POST data")
	}

	url, err := url.Parse(string(data))

	if err != nil {
		return id, 400, errors.New("invalid URL posted URLBucket")
	}

	b.Items[id] = url
	syncd.Publish(b.feed, id)

	return id, 201, nil
}

func (b URLBucket) Put(id string, body io.Reader) (int, error) {

	data, err := ioutil.ReadAll(body)

	if err != nil {
		return 400, err
	}

	url, err := url.Parse(string(data))

	if err != nil {
		return 400, errors.New("invalid URL posted URLBucket")
	}

	_, exists := b.Items[id]

	b.Items[id] = url
	syncd.Publish(b.feed, id)

	if !exists {
		return 201, nil
	}

	return 200, nil
}

func (b URLBucket) Delete(id string) (int, error) {

	delete(b.Items, id)

	return 200, nil
}

func (b URLBucket) List() (io.Reader, int, error) {

	text, err := json.Marshal(b.Items)

	if err != nil {
		return nil, 500, err
	}

	return bytes.NewBuffer(text), 200, nil
}
